﻿#pragma once

class PeakCaculator
{
public:
    int32_t len;            // x0 -> 0
    int32_t evenNumber;     // x1 -> 4
    int32_t *pRawBagBuffer; // x2 -> 8
    int32_t acc;            // x3 -> 12
    double *dblArray;       // x4 -> 16
    int32_t *intArray;      // x5 -> 20
    int32_t time;           // x6 -> 24
    int32_t unused;         // x7 -> 28
    double slope1;          // x8 -> 32
    double slope4;          // x10 -> 40
    // sub_1001C780
    PeakCaculator *init(int32_t *pRawBag, int32_t len, int32_t num)
    {
        this->pRawBagBuffer = pRawBag;
        this->len = len;
        if (num % 2)
        {
            this->evenNumber = num + 1;
        }
        else
        {
            this->evenNumber = num;
        }
        this->intArray = new int32_t[this->len];
        this->dblArray = new double[this->len];
        this->slope4 = 0;
        this->slope1 = 0;
        return this;
    }
    // sub_1001C830
    PeakCaculator *calcBaseTailTangentParams(int32_t tr)
    {
        int32_t j;
        int32_t i;
        int32_t *buf = this->pRawBagBuffer;

        j = -this->evenNumber / 2;
        this->acc = 0;
        while (j <= this->evenNumber / 2)
        {
            this->acc += buf[tr + j++];
        }
        this->intArray[0] = tr;
        this->dblArray[0] = (double)this->acc / (double)(this->evenNumber + 1);
        for (i = 1; i < this->len; ++i)
        {
            this->acc -= buf[tr++ - (this->evenNumber / 2)];
            this->acc += buf[tr + (this->evenNumber / 2)];
            this->intArray[i] = tr;
            this->dblArray[i] = (double)this->acc / (double)(this->evenNumber + 1);
        }
        this->time = tr;
        this->slope1 =
            (this->dblArray[1] - this->dblArray[0]) / (double)(this->intArray[0] - this->intArray[1]);
        this->slope4 =
            (this->dblArray[4] - this->dblArray[0]) / (double)(this->intArray[0] - this->intArray[4]);
        return this;
    }
    // sub_1001C9F0
    int32_t findBaseTailTangentPeakTime(int32_t ts, double hs, int32_t te)
    {
        double val;

        if (ts == this->intArray[0])
        {
            return -1;
        }
        while (this->evenNumber / 2 + this->len + this->time < te)
        {
            this->reCalcBaseTailTangentParam();
            val = (hs - this->dblArray[0]) / (ts - this->intArray[0]);
            if (this->slope1 > val && this->slope4 > val)
            {
                return this->time;
            }
        }
        return 0;
    }
    // sub_1001CE30
    int32_t findBaseFrontTangentPeakTime(int32_t te, double he, int32_t ts)
    {
        double val;

        if (te == this->intArray[0])
        {
            return -1;
        }
        while (this->time - this->len - this->evenNumber / 2 > ts)
        {
            this->reCalcBaseFrontTangentParam();
            val = (he - this->dblArray[0]) / (this->intArray[0] - te);
            if (this->slope1 > val && this->slope4 > val)
            {
                return this->time;
            }
        }
        return 0;
    }
    // sub_1001CC00
    PeakCaculator *shutdown(char flag)
    {
        this->clean();
        if ((flag & 1) != 0)
        {
            operator delete((void *)this);
            return NULL;
        }
        return this;
    }
    // sub_1001CC30
    void clean()
    {
        operator delete(this->dblArray);
        operator delete(this->intArray);
    }
    // sub_1001CC70
    PeakCaculator *calcBaseFrontTangentParams(int32_t tr)
    {
        int32_t j;
        int32_t i;
        int32_t *buf = this->pRawBagBuffer;

        j = this->evenNumber / 2;
        this->acc = 0;
        while (j >= -this->evenNumber / 2)
        {
            this->acc += buf[tr + j--];
        }
        this->intArray[0] = tr;
        this->dblArray[0] = (double)this->acc / (this->evenNumber + 1);
        for (i = 1; i < this->len; ++i)
        {
            this->acc -= buf[tr-- + (this->evenNumber / 2)];
            this->acc += buf[tr - (this->evenNumber / 2)];
            this->intArray[i] = tr;
            this->dblArray[i] = (double)this->acc / (this->evenNumber + 1);
        }
        this->time = tr;
        this->slope1 = (this->dblArray[1] - this->dblArray[0]) / (this->intArray[0] - this->intArray[1]);
        this->slope4 = (this->dblArray[4] - this->dblArray[0]) / (this->intArray[0] - this->intArray[4]);
        return this;
    }

    // sub_1001CEE0
    PeakCaculator *reCalcBaseFrontTangentParam()
    {
        int32_t *buf = this->pRawBagBuffer;
        memcpy((void *)&this->intArray[0], (void *)&this->intArray[1], 4 * (this->len - 1));
        memcpy((void *)&this->dblArray[0], (void *)&this->dblArray[1], 8 * (this->len - 1));
        this->acc = this->acc - buf[this->time + this->evenNumber / 2];
        this->time = this->time - 1;
        this->acc = this->acc + buf[this->time - this->evenNumber / 2];
        this->intArray[this->len - 1] = this->time;
        this->dblArray[this->len - 1] = (double)this->acc / (double)(this->evenNumber + 1);
        this->slope1 = (this->dblArray[1] - this->dblArray[0]) / (this->intArray[0] - this->intArray[1]);
        this->slope4 = (this->dblArray[4] - this->dblArray[0]) / (this->intArray[0] - this->intArray[4]);
        return this;
    }
    // sub_1001CAA0
    PeakCaculator *reCalcBaseTailTangentParam()
    {
        int32_t *buf = this->pRawBagBuffer;
        memcpy((void *)&this->intArray[0], (void *)&this->intArray[1], 4 * (this->len - 1));
        memcpy((void *)&this->dblArray[0], (void *)&this->dblArray[1], 8 * (this->len - 1));
        this->acc = this->acc - buf[this->time - this->evenNumber / 2];
        this->time = this->time + 1;
        this->acc = this->acc + buf[this->time + this->evenNumber / 2];
        this->intArray[this->len - 1] = this->time;
        this->dblArray[this->len - 1] = (double)this->acc / (this->evenNumber + 1);
        this->slope1 = (this->dblArray[1] - this->dblArray[0]) / (this->intArray[1] - this->intArray[0]);
        this->slope4 = (this->dblArray[4] - this->dblArray[0]) / (this->intArray[4] - this->intArray[0]);
        return this;
    }
};
